/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include <isa.h>
#include <cpu/cpu.h>
#include <difftest-def.h>
#include <memory/paddr.h>
struct diff_context_t {
  word_t gpr[32];
  word_t pc;
};
const int NXPR = 32;
void ref_diff_set_regs(void* diff_context) {
  struct diff_context_t* ctx = (struct diff_context_t*)diff_context;
  for (int i = 0; i < NXPR; i++) {
    cpu.gpr[i]= ctx->gpr[i];
  }
  cpu.pc = ctx->pc;
}
void ref_diff_get_regs(void* diff_context) {
  struct diff_context_t* ctx = (struct diff_context_t*)diff_context;
  for (int i = 0; i < NXPR; i++) {
    ctx->gpr[i] = cpu.gpr[i];
  }
  ctx->pc = cpu.pc;
}
void difftest_memcpy(paddr_t addr, void *buf, size_t n, bool direction) {
  if (direction == DIFFTEST_TO_REF) memcpy(guest_to_host(addr), buf, n);
  else memcpy(buf, guest_to_host(addr), n);
}

void difftest_regcpy(void *dut, bool direction) {
  if (direction == DIFFTEST_TO_REF) {
    ref_diff_set_regs(dut);
  } else {
    ref_diff_get_regs(dut);
  }
}

void difftest_exec(uint64_t n) {
  // assert(0);
  cpu_exec(n);
}

void difftest_raise_intr(word_t NO) {
  // assert(0);
 csr.mepc = cpu.pc;
  csr.mcause = NO;
  csr.mstatus=(csr.mstatus&(~(word_t)((1<<3)|(1<<7)|(3<<11))))|(((csr.mstatus>>3)&1)<<7)|((word_t)(3<<11));
  // csr.mstatus= 0x0000000a00001800;
  cpu.pc = csr.mtvec;

}
void difftest_init(int port) {
  /* Perform ISA dependent initialization. */
  init_isa();
}
